﻿using System.Collections.Generic;
using System.Web;

namespace BitworkStudios.Web.Mvc.Framework.Navigation
{
    public class Menu
    {
        public MenuItemNode RootMenu { get; set; }

        public Menu(SiteMapNode rootSiteMapNode)
        {
            RootMenu = new MenuItemNode();
            RootSiteMapNode = rootSiteMapNode;
        }

        private SiteMapNode _rootSiteMapNode;
        public SiteMapNode RootSiteMapNode
        {
            set
            {
                _rootSiteMapNode = value;
                BuilChildNodes(_rootSiteMapNode, RootMenu);
            }
        }

        private void BuilChildNodes(SiteMapNode sourceRootNode, MenuItemNode destinationRootNode)
        {
            foreach (SiteMapNode siteMapNode in sourceRootNode.ChildNodes)
            {
                var menuItemNode = new MenuItemNode
                {
                    Title = siteMapNode.Title,
                    Url = new UrlContext(siteMapNode.Url),
                    ParentNode = destinationRootNode
                };

                destinationRootNode.ChildNodes.Add(menuItemNode);
                BuilChildNodes(siteMapNode, menuItemNode);
            }
        }

        private MenuItemNode FindFirstMenuItemNodeByBreadthFirst(MenuItemNode rootMenuItemNode, SiteMapNode match)
        {
            var queue = new Queue<MenuItemNode>();
            queue.Enqueue(rootMenuItemNode);

            while (queue.Count > 0)
            {
                // Take the next node from the front of the queue
                var node = queue.Dequeue();

                // Process the node 'node'

                if (node.Url != null)
                {
                    if (node.Url.Url == match.Url)
                    {
                        return node;
                    }
                }

                // Add the node’s children to the back of the queue
                foreach (var child in node.ChildNodes)
                {
                    queue.Enqueue(child);
                }
            }

            // None of the nodes matched the specified predicate.
            return null;
        }

        private SiteMapNode _currentSiteMapNode;
        public SiteMapNode CurrentSiteMapNode
        {
            set
            {
                _currentSiteMapNode = value;
                CurrentMenuItemNode = FindFirstMenuItemNodeByBreadthFirst(RootMenu, _currentSiteMapNode);
            }
        }

        private MenuItemNode _currentMenuItemNode;
        public MenuItemNode CurrentMenuItemNode
        {
            get { return _currentMenuItemNode; }
            set
            {
                _currentMenuItemNode = value;
                ClearActiveStates();
                SetActiveState(_currentMenuItemNode);
            }
        }

        public MenuItemNode BreadCrumbs
        {
            get
            {
                var parentNode = GetParentNode(CurrentMenuItemNode);

                return CurrentMenuItemNode;
            }
        }

        public List<MenuItemNode> TopMenu
        {
            get
            {
                return RootMenu.ChildNodes;
            }
        }

        private MenuItemNode GetParentNode(MenuItemNode menuItemNode)
        {
            if(menuItemNode.ParentNode == null)
            {
                return menuItemNode;
            }

            return GetParentNode(menuItemNode);
        }

        public List<MenuItemNode> SectionMenu
        {
            get
            {
                MenuItemNode selectedRootMenuItemNode = GetSelectedRootMenuItemNode(_currentMenuItemNode);
                return selectedRootMenuItemNode.ChildNodes;
            }
        }

        private MenuItemNode GetSelectedRootMenuItemNode(MenuItemNode selectedMenuItemNode)
        {
            if (selectedMenuItemNode.ParentNode.ParentNode == null)
            {
                return selectedMenuItemNode;
            }

            return GetSelectedRootMenuItemNode(selectedMenuItemNode.ParentNode);
        }

        private MenuItemNode GetSelectedSectionMenuItemNode(MenuItemNode selectedMenuItemNode)
        {
            if (selectedMenuItemNode != GetSelectedRootMenuItemNode(selectedMenuItemNode))
            {
                if (selectedMenuItemNode.ParentNode.ParentNode.ParentNode == null)
                {
                    return selectedMenuItemNode;
                }

                return GetSelectedSectionMenuItemNode(selectedMenuItemNode.ParentNode);
            }

            return new MenuItemNode();
        }

        public List<MenuItemNode> SideMenu
        {
            get
            {
                MenuItemNode selectedSectionMenuItemNode = GetSelectedSectionMenuItemNode(_currentMenuItemNode);
                return selectedSectionMenuItemNode.ChildNodes;
            }
        }

        public void ClearActiveStates()
        {
            foreach (MenuItemNode menuItemNode in RootMenu.ChildNodes)
            {
                menuItemNode.IsActive = false;
            }
        }

        public void SetActiveState(MenuItemNode node)
        {
            node.IsActive = true;
            if (node.ParentNode != null)
            {
                SetActiveState(node.ParentNode);
            }
        }
    }
}
